package com.smatiger.hotdeploy.loader.application;

import java.io.File;

import org.apache.commons.vfs2.FileListener;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.VFS;
import org.apache.commons.vfs2.impl.DefaultFileMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smatiger.hotdeploy.loader.constants.Constants;
import com.smatiger.hotdeploy.loader.core.IApplication;
import com.smatiger.hotdeploy.loader.factory.ClassLoaderFactory;
import com.smatiger.hotdeploy.loader.factory.LoaderFactory;
import com.smatiger.hotdeploy.loader.listener.JarFileChangeListener;

/**
* @Description: 应用管理
* @author smatiger
* @date 2017年7月3日 下午4:50:08 
*/
public class ApplicationManager {
    private Logger                    logger   = LoggerFactory.getLogger(getClass());

    private static ApplicationManager instance = null;

    private LoaderFactory             loader   = null;

    private ApplicationManager() {
    }

    public void init() {
        System.out.println("init start.....");
        loader = new ClassLoaderFactory();
        createApplication(Constants.JAR_PATH);
        System.out.println("monitor file change!");
        monitorFileChangeEvent(Constants.JAR_PATH);
        System.out.println("init end!");
    }

    public void reload(String fileName) {
        System.out.println("reload start.....");
        createApplication(Constants.JAR_PATH);
        System.out.println("reload end!");
    }

    private void monitorFileChangeEvent(String classPath) {
        try {
            FileSystemManager fileSystemManager = VFS.getManager();
            File file = new File(classPath);
            FileListener fileListener = new JarFileChangeListener();
            DefaultFileMonitor defaultFileMonitor = new DefaultFileMonitor(fileListener);
            defaultFileMonitor.setRecursive(true);
            FileObject fileObject = fileSystemManager.resolveFile(file.getAbsolutePath());
            defaultFileMonitor.addFile(fileObject);
            defaultFileMonitor.start();
            System.out.println("Now to listen " + fileObject.getName().getPath());
        } catch (FileSystemException e) {
            logger.error("FileSystemException", e);
        }
    }

    private void createApplication(String classPath) {
        ClassLoader classLoader = loader.getLoader().createClassLoader(
            this.getClass().getClassLoader(), classPath);
        try {
            Class<?> classzs = classLoader.loadClass(Constants.JAR_FILE_CLASS);
            IApplication application = (IApplication) classzs.newInstance();
            application.init();
        } catch (ClassNotFoundException e) {
            logger.error("ClassNotFoundException", e);
        } catch (InstantiationException e) {
            logger.error("InstantiationException", e);
        } catch (IllegalAccessException e) {
            logger.error("IllegalAccessException", e);
        }
    }

    private synchronized static void syncInit() {
        if (instance == null) {
            instance = new ApplicationManager();
        }
    }

    public static ApplicationManager getInstance() {
        if (instance == null) {
            syncInit();
        }
        return instance;
    }
}